<template>
  <template v-if="modelValue"
    ><teleport to=".dialog-main">
      <div class="pickPer" v-show="showDialog">
        <transition name="fade">
          <div ref="pickPerRef" class="pickPer-main" v-show="showDialogContent">
            <ul>
              <li v-for="{ id, value } in menuData">
                <div class="pickPer-main__item" @click="pickPermission(id)">
                  <span
                    :class="{
                      'pick-hook': true,
                      'pick-hook__checked': pickValue.type === id,
                      'pick-hook__noCheck': pickValue.type !== id,
                    }"
                  ></span>
                  <span>{{ value }}</span>
                </div>
              </li>
            </ul>
            <transition name="fade">
              <ul v-show="showTwoMenu" class="pickPer-children">
                <li
                  v-for="item in [{ value: '分组' }, { value: '朋友' }]"
                  :key="item.value"
                >
                  <div class="pickPer-main__item" @click="pickPerType(item.value)">
                    <span
                      :class="{
                        'pick-hook': true,
                        'pick-hook__checked': pickValue.childrenType === item.value,
                        'pick-hook__noCheck': pickValue.childrenType !== item.value,
                      }"
                    ></span>
                    <span>{{ item.value }}</span>
                  </div>
                </li>
              </ul></transition
            >
            <transition name="fade">
              <div v-show="showGroup" class="pickPer-children">
                <el-scrollbar v-if="showGroupContent" :max-height="124">
                  <ul>
                    <li v-for="group in groups.value" :key="group">
                      <div
                        class="pickPer-main__item pickPer-main__item--three"
                        @click="startCheck(group)"
                      >
                        <span
                          :class="{
                            'pick-hook': true,
                            'pick-hook__checked': pickValue.children.has(group),
                            'pick-hook__noCheck': !pickValue.children.has(group),
                          }"
                        ></span>
                        <span class="pickPer-groupName" :title="group">{{ group }}</span>
                      </div>
                    </li>
                  </ul></el-scrollbar
                >
                <div class="pickPer-main__loading flex" v-else-if="isRequesting">
                  <SvgIcon icon-class="loadingGray" popper-class="loadingIcon spinMess" />
                </div>
                <div class="pickPer-main__loading--error flex" v-else-if="isError">
                  <div>
                    <p>请求失败</p>
                    <p>点击 <span @click="getGroupData">重试</span></p>
                  </div>
                </div>
              </div></transition
            >
            <transition name="fade">
              <div v-show="showFriend" class="pickPer-friends">
                <el-scrollbar v-if="showFriendContent" :max-height="300">
                  <ul class="pickPer-friends__list">
                    <li v-for="[initials, { value }] in friends" :key="initials">
                      <div class="friends-item__initials">{{ initials }}</div>
                      <ul>
                        <li
                          class="friends-item"
                          v-for="[key, { avatar, remark }] in value"
                          :key="key"
                          @click="startCheck(key)"
                        >
                          <div
                            :class="{
                              flex: true,
                              'friends-check': true,
                              isChecked: props.pickValue.children.has(key),
                              noChecked: !props.pickValue.children.has(key),
                            }"
                          >
                            <SvgIcon popper-class="icon-checked" icon-class="check" />
                          </div>
                          <img class="friends-item__avatar" :src="avatar" alt="" />
                          <span class="friends-item__remark" :title="remark">{{
                            remark
                          }}</span>
                        </li>
                      </ul>
                    </li>
                  </ul>
                </el-scrollbar>
                <div class="pickPer-friends__loading flex" v-else-if="isRequesting">
                  <SvgIcon icon-class="loadingGray" popper-class="loadingIcon spinMess" />
                </div>
                <div class="pickPer-friends__loading--error flex" v-else-if="isError">
                  请求失败，点击
                  <span @click="getFriendsData">重试</span>
                </div>
              </div>
            </transition>
          </div></transition
        >
      </div>
    </teleport></template
  >
</template>

<script lang="ts" setup>
import { ref, watchEffect, nextTick } from "vue";
import menuData from "@/staticDatas/pickPermission";
import { useFriendPinia } from "@/pinia/friend";
import { storeToRefs } from "pinia";
import { Base64 } from "js-base64";

const props = defineProps<{
  modelValue: boolean;
  mouseCoord: { x: number; y: number };
  pickValue: {
    tag: "全部" | "私密" | "部分可看" | "谁不能看";
    type: 0 | 1 | 2 | 3;
    childrenType: "分组" | "朋友" | "";
    children: Set<string>;
  };
  userId: string;
}>();

const emits = defineEmits<{
  (e: "update:modelValue", show: boolean): void;
}>();

const friendStore = useFriendPinia();
const { groups } = storeToRefs(friendStore);

/**
 * 是否显示确认操作的对话框
 */
const showDialog = ref<boolean>(false);
/**
 * 是否显示确认操作的对话框的内容
 */
const showDialogContent = ref<boolean>(false);
/**
 * 是否显示二级菜单
 */
const showTwoMenu = ref<boolean>(false);
/**
 * 是否显示分组菜单
 */
const showGroup = ref<boolean>(false);
/**
 * 是否显示朋友菜单
 */
const showFriend = ref<boolean>(false);

/**
 * 给该组件的内容元素一个ref属性
 */
const pickPerRef = ref<HTMLUListElement>();
/**
 * 是否正在请求分组或者好友数据
 */
const isRequesting = ref<boolean>(false);

/**
 * 判断用户所点击的元素是否符合标准
 */
const judgeClick = (e: Event) => {
  const target: HTMLElement = e.target as HTMLElement;
  if (!pickPerRef.value?.contains(target) && !isRequesting.value)
    emits("update:modelValue", false);
};

// 设置该组件的位置
const setPosition = () => {
  const fatherEle: HTMLElement = document.body.getElementsByClassName(
    "dialog-main"
  )[0] as HTMLElement;
  const rect = fatherEle.getBoundingClientRect();
  pickPerRef.value!.style.cssText += `top: ${
    props.mouseCoord.y - pickPerRef.value!.offsetHeight - rect.y
  }px; left: ${props.mouseCoord.x - rect.x}px;`;
};

watchEffect(() => {
  if (props.modelValue) {
    showDialog.value = true;
    nextTick(() => {
      showDialogContent.value = true;
      nextTick(() => setPosition());
    });
    setTimeout(() => document.addEventListener("click", judgeClick), 200);
  } else {
    showTwoMenu.value = false;
    showGroup.value = false;
    showFriend.value = false;
    showDialogContent.value = false;
    setTimeout(() => (showDialog.value = false), 200);
    document.removeEventListener("click", judgeClick);
    if (
      props.pickValue.type !== 0 &&
      props.pickValue.type !== 1 &&
      !props.pickValue.children.size
    ) {
      props.pickValue.tag = "全部";
      props.pickValue.type = 0;
      props.pickValue.childrenType = "";
    }
  }
});

// 选择对应选项后的操作
const seleExecute = (
  tag: "全部" | "私密" | "部分可看" | "谁不能看",
  type: 0 | 1 | 2 | 3
) => {
  if (props.pickValue.tag !== tag) {
    props.pickValue.tag = tag;
    props.pickValue.type = type;
    props.pickValue.childrenType = "";
    if (tag === "全部" || tag === "私密") {
      props.pickValue.children.clear();
      showTwoMenu.value = false;
    }
    showFriend.value = false;
    showGroup.value = false;
  }
};

/**
 * 用户开始选择权限
 * @param type 0代表全部，1代表私密，2代表部分可看，3代表谁不能看
 */
const pickPermission = (type: 0 | 1 | 2 | 3) => {
  if (isRequesting.value) return;
  switch (type) {
    case 0:
      seleExecute("全部", 0);
      break;
    case 1:
      seleExecute("私密", 1);
      break;
    case 2:
      props.pickValue.tag === "谁不能看" && props.pickValue.children.clear();
      showTwoMenu.value = true;
      seleExecute("部分可看", 2);
      break;
    case 3:
      props.pickValue.tag === "部分可看" && props.pickValue.children.clear();
      showTwoMenu.value = true;
      seleExecute("谁不能看", 3);
      break;
  }
};

/**
 * 请求是否出错
 */
const isError = ref<boolean>(false);
/**
 * 是否显示分组数据内容
 */
const showGroupContent = ref<boolean>(false);
/**
 * 是否显示朋友数据内容
 */
const showFriendContent = ref<boolean>(false);

// 请求分组数据
const getGroupData = () => {
  if (!isRequesting.value) {
    if (isError.value) isError.value = false;
    isRequesting.value = true;
    friendStore
      .getUserGroups({ page: 0 })
      .then((data) => {
        isRequesting.value = false;
        if (data.code === 1) showGroupContent.value = true;
        else isError.value = true;
      })
      .catch(() => {
        isRequesting.value = false;
        isError.value = true;
      });
  }
};

/**
 * 朋友圈权限为可看的好友数据
 */
const friends = ref<Map<string, Friend>>(new Map());
// 请求朋友数据
const getFriendsData = () => {
  if (!isRequesting.value) {
    if (showFriendContent.value) showFriendContent.value = false;
    if (isError.value) isError.value = false;
    isRequesting.value = true;
    friendStore
      .getAllFriends({ slefId: Base64.encode(props.userId), filter: true })
      .then((data) => {
        isRequesting.value = false;
        if (data.code === 1) {
          friends.value = data.friendsData;
          showFriendContent.value = true;
        } else isError.value = true;
      })
      .catch(() => {
        isRequesting.value = false;
        isError.value = true;
      });
  }
};

// 选择权限类型，是分组还是朋友
const pickPerType = (type: any) => {
  if (isRequesting.value) return;
  else {
    let boo: boolean = false;
    if (type === "分组") {
      boo = showFriend.value;
      showFriend.value = false;
      boo ? setTimeout(() => (showGroup.value = true), 200) : (showGroup.value = true);
    } else {
      boo = showGroup.value;
      showGroup.value = false;
      boo ? setTimeout(() => (showFriend.value = true), 200) : (showFriend.value = true);
    }
    if (type === props.pickValue.childrenType) return;
  }
  if (type === "朋友")
    props.pickValue.childrenType === "分组" && props.pickValue.children.clear();
  else if (props.pickValue.childrenType === "朋友") props.pickValue.children.clear();
  props.pickValue.childrenType = type;
  switch (props.pickValue.childrenType) {
    case "分组":
      groups.value.currentPage !== groups.value.maxPage
        ? getGroupData()
        : (showGroupContent.value = true);
      break;
    case "朋友":
      getFriendsData();
      break;
  }
};

// 勾选分组或者朋友
const startCheck = (value: string) =>
  props.pickValue.children.has(value)
    ? props.pickValue.children.delete(value)
    : props.pickValue.children.add(value);
</script>

<style lang="scss" scoped>
.fade {
  @include fade(0.18s, ease);
}

.pickPer {
  position: absolute;
  inset: 0;

  @mixin spanOverFlow($width) {
    display: inline-block;
    max-width: $width;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  &-main {
    position: absolute;
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
    font-size: 14px;
    padding: 2px 2px 1px 2px;
    display: flex;
    background-color: #fff;

    %pickIcon {
      background-color: #5ec02d;
      border-color: transparent;

      &::after {
        opacity: 1;
      }
    }

    %retryHover {
      transition: color 0.2s;

      &:hover {
        cursor: pointer;
        color: rgb(250, 12, 12);
        text-decoration: underline;
      }
    }

    &__item {
      @include setWidHei(100px, 30px);
      line-height: 30px;
      box-sizing: border-box;
      padding-left: 10px;
      margin-bottom: 1px;
      white-space: nowrap;
      cursor: pointer;
      transition: background-color 0.2s;
      display: flex;
      align-items: center;

      &:hover {
        .pick-hook__noCheck {
          @extend %pickIcon;
        }
      }

      .pick-hook {
        position: relative;
        display: inline-block;
        margin-right: 6px;
        @include setWidHei(10px, 10px);
        border: 1px solid #e0e0e0;
        border-radius: 50%;
        transition: background-color 0.6s, border-color 0.2s;

        &::after {
          content: "";
          @include setWidHei(5px, 5px);
          border-radius: 50%;
          background-color: #fff;
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          transition: opacity 0.5s;
          opacity: 0;
        }

        &__checked {
          @extend %pickIcon;
        }
      }

      &--three {
        width: 120px;

        .pickPer-groupName {
          @include spanOverFlow(75%);
        }
      }
    }

    &__loading {
      @include setWidHei(100px, 100%);

      .loadingIcon {
        font-size: 25px;
      }

      &--error {
        @include setWidHei(100px, 100%);

        p {
          margin: 5px 0;

          &:last-child {
            span {
              @extend %retryHover;
            }
          }
        }
      }
    }
  }

  &-children {
    &::before {
      content: "";
      position: absolute;
      top: 0;
      bottom: 0;
      border-left: 1px solid #dcdfe6;
    }
  }

  &-friends {
    position: absolute;
    top: 50%;
    left: calc(100% + 10px);
    transform: translateY(-50%);
    width: 220px;
    background-color: #fff;
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);
    border-radius: 4px;
    padding: 4px 0;

    &__loading {
      height: 60px;

      .loadingIcon {
        font-size: 30px;
      }

      &--error {
        height: 60px;

        span {
          margin-left: 6px;
          @extend %retryHover;
        }
      }
    }

    &__list {
      margin: 5px 0;

      .friends {
        &-item {
          display: flex;
          align-items: center;
          padding: 10px 25px 10px 28px;
          cursor: pointer;
          transition: background-color 0.75s;

          &:hover {
            background-color: rgba(154, 152, 152, 0.114);
          }

          &__initials {
            padding: 8px 0 6px 20px;
            color: #8e8e8e;
          }

          &__avatar {
            @include setWidHei(35px, 35px);
            object-fit: cover;
            border-radius: 50%;
            margin-right: 15px;
          }

          &__remark {
            white-space: nowrap;
            @include spanOverFlow(80px);
          }
        }

        &-check {
          @include setWidHei(14px, 14px);
          margin-right: 10%;
          transition: background-color 0.25s;
        }
      }
    }
  }
}
</style>
